C# – Creating a Service to Monitor a Directory
Let’s say you wanted to watch a directory and perform an action each time a file is added, deleted, changed, or renamed.
- Microsoft has a Visual C# Windows Service project template in Visual Studio.
- Microsoft also has a nice class already created to help with this: FileSystemWatcher
Example Project
Here is an example project you can download: DirectoryMonitoring.zip
Step 1 – Create a Visual C# Windows Service project in Visual Studio
- Select File | New Project.
- Select Templates | VIsual C# | Windows | Windows Service.
- Provide a name: DirectoryMonitoring
- Click OK.
Step 2 – Create an object that inherits from FileSystemWatcher
- Right-click on Project and choose Add | Class.
- Name it MyFileSystemWatcher.cs.
using System; using System.IO; namespace DirectoryMonitoring { public class MyFileSystemWatcher : FileSystemWatcher { public MyFileSystemWatcher() { Init(); } public MyFileSystemWatcher(String inDirectoryPath) : base(inDirectoryPath) { Init(); } public MyFileSystemWatcher(String inDirectoryPath, string inFilter) : base(inDirectoryPath, inFilter) { Init(); } private void Init() { IncludeSubdirectories = true; // Eliminate duplicates when timestamp doesn't change NotifyFilter = NotifyFilters.FileName | NotifyFilters.Size; // The default also has NotifyFilters.LastWrite EnableRaisingEvents = true; Created += Watcher_Created; Changed += Watcher_Changed; Deleted += Watcher_Deleted; Renamed += Watcher_Renamed; } public void Watcher_Created(object source, FileSystemEventArgs inArgs) { Log.WriteLine("File created or added: " + inArgs.FullPath); } public void Watcher_Changed(object sender, FileSystemEventArgs inArgs) { Log.WriteLine("File changed: " + inArgs.FullPath); } public void Watcher_Deleted(object sender, FileSystemEventArgs inArgs) { Log.WriteLine("File deleted: " + inArgs.FullPath); } public void Watcher_Renamed(object sender, RenamedEventArgs inArgs) { Log.WriteLine("File renamed: " + inArgs.OldFullPath + ", New name: " + inArgs.FullPath); } } }
Notice that each method is logging. We will implement this log next.
Step 3 – Add logging
- Add the class from a previous post: A simple Log singleton in C#
- Make sure to change the namespace to match.
Step 4 – Implement the Service
- Right-click on the Service1.cs file and choose View Code.
- Change both the Name and the ServiceName to DirectoryMonitoringService. You can right-click on the file to rename. If that doesn’t rename the class, you can open the file, right-click on the class name and choose Refactor | Rename.
- Go to the code of the DirectoryMonitoringService.cs file (which was Service1.cs just a couple steps ago) in Visual Studio.
- Implement the constructor as follows:
using System.IO; using System.ServiceProcess; namespace DirectoryMonitoring { public partial class DirectoryMonitoringService: ServiceBase { protected FileSystemWatcher Watcher; // Directory must already exist unless you want to add your own code to create it. string PathToFolder = @"C:\Directoy\To\Monitor"; public DirectoryMonitoringService() { Log.Instance.LogPath = @"C:\ProgramData\DirectoryMonitoring"; Log.Instance.LogFileName = "DirectoryMonitoring"; Watcher = new MyFileSystemWatcher(PathToFolder); } protected override void OnStart(string[] args) { } protected override void OnStop() { } } }
Step 5 – Create a Service Installer
- Right-click on DirectoryMonitoringService.cs and choose View Designer.
- Right-click anywhere in the designer window and choose Add Installer. This adds a ProjectInstaller.cs file.
- Right-click on ProjectInstaller.cs and choose View Designer.
- In the designer, right-click on serviceProcessInstaller1 and choose Properties.
- In the properties, set Account to LocalSystem.
- Back in the designer, right-click on serviceInstaller1 and choose Properties.
- Set StartType to Automatic.
- Add a descriptions if you want.
Step 6 – Install the Service
- Open the Developer Command Prompt by right-clicking and choosing Run as Administrator.
Note: If you don’t have the Developer Command Prompt, you can open a normal command prompt as administration and get installUtil.exe from this path:c:\Windows\Microsoft.NET\Framework64\v4.0.30319\installutil.exe
- In the command prompt, change to the bin\debug folder in your project directory.
- Run this command to install the service:
installutil.exe DirectoryMonitoring.exe
- Start the service with this command.
net start DirectoryMonitoringService
Step 7 – Debug the Service
- Make sure the service is started and running.
- In Visual Studio with the DirectoryMonitoring project open, click Debug | Attach to Process.
- Select the DirectoryMonitoring.exe file.
- Put a break point at each event in the MyFileSystemWatcher object.
- Test all four events:
- Add a file.
- Rename a file.
- Open and save a file.
- Delete a file.
You have now created a service to monitor a directory and you have seen how to debug it.
What's Happening i am new to this, I stumbled upon this
I've discovered It absolutely useful and it has
helped me out loads. I am hoping to give a contribution & assist other users like its
helped me. Good job.
https://3dwarehouse.sketchup.com/user/4c3430ff-0769-48ee-9d9a-c03a8abbed6c/Sabah-M
Great tutorial. Just one question. "why does saving a file to c:\myWatchFolder\TestFileforMonitor.txt.txt trigger the create/insert and delete twice events ? "
I downloaded the sample code , and added by own logwriter to write more inArgs data, and got the following:
=====================================================
File INSERTED C:\$$$$\zzzz.txt
Date 22/07/2016 11:03:11
ChangeType INSERTED Created
Hashcode INSERTED 11454272
=====================================================
File Deleted C:\$$$$\zzzz.txt
Date 22/07/2016 11:03:11
ChangeType Deleted Deleted
Hashcode Deleted 65934242
=====================================================
File INSERTED C:\$$$$\zzzz.txt
Date 22/07/2016 11:03:11
ChangeType INSERTED Created
Hashcode INSERTED 33044831
=====================================================
File Modified C:\$$$$\zzzz.txt
Date 22/07/2016 11:03:11
ChangeType Modified Changed
Hashcode Modified 18776029
=====================================================
This is a known bug. I'm sure if you google around you can find it.
I had to detect the first one, set a value to true (_IsProcessing) so that the second one didn't fire. Then I had to enhance it so the _IsProcessing only worked for the one file, in case two files were modified at a time. I think I used a dictionary, added the file, then on completion removed the file.
[…] último, recomiendo añadir un ProjectInstaller.cs a vuestro servicio tal como explica este enlace en el paso 5. Añadirlo nos permitirá entre otras cosas especificar el tipo de cuenta, el nombre y […]
I would like to check whether it is possible to detect the computer name of which the changes (files moved, deleted, copied, renamed etc) are made.
When I copy a folder in to the folder that is being monitored, why is their a created and changed event? please help.
Also when i'm deleting files it logs as changed?
File created or added: C:\monitor\lg\20150716_125413.jpg
File changed: C:\monitor\lg\20150716_125413.jpg
Thank you for this great tutorial, helped me a bunch creating a custom service for my self.
I have one problem though, before I made this service I made a similar windows forms application doing all the actions which I've put in my service project, but everytime a new file is put in the watch folder it does it's job and stops the service.
this isn't the way it should be is it?
any Ideas on how to fix this?
Nevermind, I found the bug my self, thanks to your tut on debug 🙂
Anyways great work! thanks
Thanks for the great example, is there a way to add ftp action to your service? Like anytime a file is created in the directory have ftp send it somewhere else?
How do you solved this? I'm having same issue and can't figure this out.
Just combine this post with my ftp post: How to upload a fil to an ftp server using C#
Thanks, Mr. Barneck. Your examples were very helpful in implementing our own file system watcher.
Hi,
Great article but I am a newbie and I am stuck at Step 4.2. When I double click to service1.cs, I see a gray screen. WHere is the name and the service name to be changed?
Best Regards,
Sam
I updated the steps. Hope that is clearer.
I really appreciate this article. Very helpful at the right time.
Hi Rhyous,
It's a nice Article. Could you also tell me if we can monitor the folder for a certain amoutn of time. Let's take an example: I want to monitor the folder/Directory continuously if there is nothing happening for 10 mins i want to raise an alert. Is that possible? If yes please let me know.
It will take work. There will not be an event automatically raised that I know of, so you will have to create a timer thread yourself and raise an event yourself. Create a Dictionary where the string is the path to the folder and the Date is the last changed time. Then have your timer thread check ever n seconds, where n is configurable. Maybe you only check every 10 minutes so n is 600.
Hi Rhyous,
Thx a lot for this excellent tutorial!!! I have playing around with this feature of C#, but never got it to work properly. Other tuts were not that clear. But you saved me day!
I was wondering, could your Log class be used to log everything to the Services' own log under the Applications and Services Logs in th Eventviewer instead of to a textfile.
If not, do you maybe have an example of how this can be done?
Thx again anyway!!!
Gijs
Yes, there is an example on Microsoft's site of logging to event viewer.
http://msdn.microsoft.com/en-us/library/zt39148a.aspx
Hi Rhyous,
I trying to added the code from the link you suggested to the Log.cs of your demo app.
But for some reason i do not get it to work... 🙁
Would it be possible for you to point me in the right direction?
Thx again!
Gijs
nice posting... it works on our own Local System, say on Drive C:\ or Drive D:\
say if I want to monitor directory on server drive, say Drive P:\, which my local system is able to access, how can I do it?
You probably have the drive mapped so you think the service has access to that share. Unfortunately that is not the case. Only your currently logged in user has access to the share. When the service runs, it runs as LocalSystem. LocalSystem does not have access to shares that you as a user have authenticated too.
If you want to monitor a network drive you must first Authenticate. So your options are to add code to authenticate to the drive first (see this article: C# Class to establish a network connection with credentials) or run your service as a user that has access to the share.
Another article that may help you is this one: How to open a command prompt running as Local System on Windows 7? By opening a command prompt as LocalSystem, you can test and verify how things work differently as LocalSystem versus how they work as your user.